package com.Vclub.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;

import com.Vclub.dao.GenericDao;
import com.Vclub.util.HibernateUtil;

public class GenericDaoImpl<T, Key extends Serializable> implements
		GenericDao<T, Key> {
	private Class<T> clasePersistente;

	@SuppressWarnings("unchecked")
	public GenericDaoImpl() {
		this.clasePersistente = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public Class<T> getClasePersistente() {
		return clasePersistente;
	}

	public void insertar(T obj) throws Exception {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();
		try {

			session.save(obj);

			transaction.commit();
			session.close();
		} catch (Exception e) {
			transaction.rollback();
			session.close();
			throw e;
		}
	}

	public void actualizar(T obj) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		session.update(obj);

		transaction.commit();
		session.close();
	}

	public void eliminar(T obj) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		session.delete(obj);

		transaction.commit();
		session.close();
	}

	public void eliminarPorIdentificador(Key identificador) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		T obj = buscarPorIdentificador(identificador);
		session.delete(obj);

		transaction.commit();
		session.close();
	}

	@SuppressWarnings("unchecked")
	public T buscarPorIdentificador(Key identificador) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		T obj = (T) session.get(this.getClasePersistente(), identificador);

		transaction.commit();
		session.close();

		return obj;
	}

	@SuppressWarnings("unchecked")
	public List<T> buscarPorEjemplo(T ejemplo, String... noIncluirPropiedades) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		Criteria criteria = session.createCriteria(ejemplo.getClass());

		Example example = Example.create(ejemplo);
		for (String propiedad : noIncluirPropiedades) {
			example.excludeProperty(propiedad);
		}
		// Excluye las props vacias
		example.excludeZeroes();
		criteria.add(example);
		List<T> resultados = criteria.list();

		transaction.commit();
		session.close();

		return resultados;
	}

	@SuppressWarnings("unchecked")
	public List<T> consultarTodos() {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		Criteria criteria = session.createCriteria(getClasePersistente());
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

		List<T> resultados = criteria.list();

		transaction.commit();
		session.close();

		return resultados;
	}

	@SuppressWarnings("unchecked")
	public List<T> consultarTodosAsc(String attribute) {
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();

		Criteria criteria = session.createCriteria(getClasePersistente());
		criteria.addOrder(Order.asc(attribute));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

		List<T> resultados = criteria.list();

		transaction.commit();
		session.close();

		return resultados;

	}

}
